/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package clusterAnalysis;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import jsc.independentsamples.MannWhitneyTest;
import jsc.onesample.Ttest;
import jsc.tests.H1;
import org.uncommons.maths.random.MersenneTwisterRNG;

/**
 *
 * @author jamie
 */
public class GeneRepeatStats {

    private TreeMap<Integer, List<Integer>> geneMap;
    private int iterations = 10000;

    public GeneRepeatStats(TreeMap<Integer, List<Integer>> geneMap) {
        this.geneMap = geneMap;
    }

    public TreeMap<Integer, List<Integer>> getRandomGeneMap(MersenneTwisterRNG rng, List<Integer> clusterSizes, List<Integer> allGenes) {
        TreeMap<Integer, List<Integer>> randomMap = new TreeMap<Integer, List<Integer>>();
        List<Integer> allGenes_clone = new ArrayList<Integer>();
        allGenes_clone.addAll(allGenes);
        for (int i = 0; i < clusterSizes.size(); i++) {
            int clusterSize = clusterSizes.get(i);
            randomMap.put(i+1, new ArrayList<Integer>());
            for (int j = 0; j < clusterSize; j++) {
                int randomIndex = rng.nextInt(allGenes_clone.size());
                int randomId = allGenes_clone.remove(randomIndex);
                randomMap.get(i+1).add(randomId);
            }
        }
        return randomMap;
    }

    public void doRepeatGeneCalculations() {
        
        doPermutations();
        
    }

    public void doPermutations(){
        int noOfRepeatGenesInClusters = getNoOfRepeatGenesInClusters(geneMap);
        int noOfRepeatGenesOverall = getNoOfRepeatGenesTotal(geneMap);
        System.out.println(noOfRepeatGenesInClusters + " repeated genes in clusters from a total of " + noOfRepeatGenesOverall + " repeated genes");

        List<Integer> clusterSizes = getClusterSizes(geneMap);
        MersenneTwisterRNG rng = new MersenneTwisterRNG();
        List<Integer> allGenes = getAllGenes(geneMap);
        List<Integer> randRepeatCounts = getRandomRepeatGeneCounts(clusterSizes, rng, allGenes);
        Ttest ttest = new Ttest(asDoubles(randRepeatCounts), noOfRepeatGenesInClusters);
        System.out.println(ttest.getSP()+", t="+ttest.getStatistic()+", "+noOfRepeatGenesInClusters+" compared to mean "+ttest.getMean());
    }

    private List<Integer> getRandomRepeatGeneCounts(List<Integer> clusterSizes, MersenneTwisterRNG rng, List<Integer> allGenes) {
        List<Integer> repeatGeneCounts = new ArrayList<Integer>();
        for(int i=0;i<iterations;i++){
            TreeMap<Integer, List<Integer>> rand = getRandomGeneMap(rng, clusterSizes, allGenes);
            int noOfRepeatGenesInClusters = getNoOfRepeatGenesInClusters(rand);
            repeatGeneCounts.add(noOfRepeatGenesInClusters);
            System.out.println(noOfRepeatGenesInClusters+" in rand permutation");
            
        }
        return repeatGeneCounts;
    }

//    private double[] getUValues(List<Integer> clusterSizes, MersenneTwisterRNG rng, List<Integer> allGenes) {
//        double[] uValues = new double[iterations];
//
//        for(int i=0;i<iterations;i++){
//            TreeMap<Integer, List<Integer>> rand = getRandomGeneMap(rng, clusterSizes, allGenes);
//            List<Integer> distB = getGeneRepeatDistribution(rand);
//            double[] doublesB  = asDoubles(distB);
//            List<Integer> distA = getGeneRepeatDistribution(rand);
//            double[] doublesA  = asDoubles(distA);
//            MannWhitneyTest mwut = new MannWhitneyTest(doublesA, doublesB, H1.GREATER_THAN);
//            uValues[i] = mwut.getStatistic();
//        }
//        return uValues;
//    }

    private List<Integer> getGeneRepeatDistribution(TreeMap<Integer, List<Integer>> geneMap) {
        List<Integer> distribution = new ArrayList<Integer>();
        for (int clusterId : geneMap.keySet()) {
            List<Integer> clusterGenes = geneMap.get(clusterId);
            Map<Integer, Integer> repeats = getGeneRepeats(clusterGenes);
            distribution.addAll(repeats.values());

        }
        return distribution;
    }

    private int getNoOfRepeatGenesInClusters(Map<Integer, List<Integer>> geneMap) {
        int total = 0;
        for (int clusterId : geneMap.keySet()) {

            List<Integer> clusterGenes = geneMap.get(clusterId);
            int noGenes = getNoOfRepeatGenes(clusterGenes);
            total += noGenes;

        }
        return total;
    }

    private int getNoOfRepeatGenesTotal(Map<Integer, List<Integer>> geneMap) {
        
        int noGenes = getNoOfRepeatGenes(getAllGenes(geneMap));
        return noGenes;
    }

    private int getNoOfRepeatGenes(List<Integer> geneIds) {
        Map<Integer, Integer> geneRepeats = getGeneRepeats(geneIds);
        int total = 0;
        for (int gId : geneRepeats.keySet()) {
            if (geneRepeats.get(gId) > 1) {
//                System.out.println(geneRepeats.get(gId));
                total++;
            }
        }
        return total;
    }

    private Map<Integer, Integer> getGeneRepeats(List<Integer> geneIds) {
        Map<Integer, Integer> repeats = new TreeMap<Integer, Integer>();
        for (int gId : geneIds) {
            if (!repeats.containsKey(gId)) {
                repeats.put(gId, 0);
            }
            repeats.put(gId, repeats.get(gId) + 1);
        }
        return repeats;
    }

    private List<Integer> getClusterSizes(TreeMap<Integer, List<Integer>> geneMap) {
        List<Integer> sizes =  new ArrayList<Integer>();
        for(List<Integer> cluster : geneMap.values()){
            sizes.add(cluster.size());
        }
        return sizes;
    }

    private List<Integer> getAllGenes(Map<Integer, List<Integer>> geneMap){
        List<Integer> allGenes = new ArrayList<Integer>();
        for (int clusterId : geneMap.keySet()) {

            allGenes.addAll(geneMap.get(clusterId));

        }
        return allGenes;
    }

    private double[] asDoubles(List<Integer> distA) {
        double[] doubles = new double[distA.size()];
        for(int i=0;i<distA.size();i++){
            doubles[i] = distA.get(i);
        }
        return doubles;
    }




}
